package com.buddy.summary.code.classloading;

import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class ClazzLoader {

    /**
     * 不同的类加载器对instanceof关键字运算的结果的影响
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    @Test
    public void clazzLoaderTest() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //自定义类加载器，可以用来加载与自己在同一路径下的Class文件
        ClassLoader myClassLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                try {
                    String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                    InputStream inputStream = getClass().getResourceAsStream(fileName);
                    if (inputStream == null)
                        return super.loadClass(name);
                    byte[] bytes = new byte[inputStream.available()];
                    inputStream.read(bytes);
                    return defineClass(name, bytes, 0, bytes.length);
                } catch (IOException e) {
                    throw new ClassNotFoundException();
                }
            }
        };


        //使用ClazzLoader的类加载器加载本类
        /**
         * 使用系统加载主类ClazzLoader的类加载器加载ClazzLoader
         * 输出显示，obj的所属类型检查正确
         * 这是虚拟机中有2个ClazzLoader类:
         *      一个是主类，另一个是main()方法中加载的类
         * 由于这两个类使用同一个类加载器加载并且来源于同一个Class文件，因此这两个类是完全相同的。
         */
        Object obj = ClazzLoader.class.getClassLoader().
                loadClass("com.buddy.summary.code.classloading.ClazzLoader").newInstance();
        System.out.println(obj.getClass());
        System.out.println(obj instanceof com.buddy.summary.code.classloading.ClazzLoader);

        //使用自定义类加载器加载本类
        /**
         * 使用自定义的类加载器myClassLoader加载ClazzLoader
         * obj2确实是类com.buddy.summary.code.classloading.ClazzLoader实例化出来的对象
         * 但是第二句输出false
         * 此时虚拟机中有3个ClazzLoader类，由于第3个类的类加载器与前面2个类加载器不同
         * 虽然来源于同一个Class文件，但它是一个独立的类，所属类型检查的返回结果自然是false。
         */
        Object obj2 = myClassLoader.loadClass("com.buddy.summary.code.classloading.ClazzLoader").newInstance();
        System.out.println(obj2.getClass());
        System.out.println(obj2 instanceof com.buddy.summary.code.classloading.ClazzLoader);
    }

}
